<?php

namespace app\service;

use Swoole\Coroutine\MySQL;
use Swoole\Coroutine\Channel;
use function Swoole\Coroutine\run;

/**
 * Swoole 实现Mysql数据库协程连接池
 * @package app\service
 */
class MysqlPool {
    //定义最大连接数
    protected $size = 8;

    //定义存放连接对象的通道
    protected $pool;

    //配置信息，数据库的配置信息
    private $config;

    //保存唯一实例的静态变量(实现连接池，一般会使用单例模式,否则每次new的时候都需要创建8个连接)
    private static $instance;

    /**
     * 构造函数(私有)
     * @param $config
     */
    private function __construct($config) {
        if (!$this->pool) {
            //通过协程来创建,run 协程容器
            run(function () use ($config) {
                //判断config是否有size
                if (isset($config['size']) && $config['size']) {
                    $this->size = $config['size'];
                }
                //创建通道对象
                $this->pool = new Channel($this->size);
                //循环创建连接对象
                for ($i = 0; $i < $this->size; $i++) {
                    //在协程中创建数据库
                    go(function () use ($config) {
                        $swoole_mysql = new MySQL();
                        $swoole_mysql->connect([
                            'host' => $config['host'],
                            'port' => $config['port'],
                            'user' => $config['user'],
                            'password' => $config['password'],
                            'database' => $config['dbname'],
                            'charset' => $config['charset'],
                        ]);
                        if ($swoole_mysql->connect_errno != 0) {
                            throw new \RuntimeException('mysql connect error');
                        } else {
                            $this->pool->push($swoole_mysql);
                        }
                    });
                }
            });
        }
    }

    /**
     * 因为构造函数是私有的，所以需要一个公共入口
     * @param array $config
     * @return MysqlPool
     */
    public static function getInstance($config = []) {
        //判断实例是否已存在
        if (!self::$instance) {
            if (!$config) {
                throw new \RuntimeException('config error');
            }
            self::$instance = new self($config);
        }
        return self::$instance;
    }

    /**
     * 获取连接对象
     * @return mixed
     */
    public function get() {
        //通过协程来实现
        run(function () {
            go(function () {
                //先判断是否有空闲的
                if ($this->pool->length() > 0) {
                    $this->mysql = $this->pool->pop();
                    if (!$this->mysql) {
                        throw new \RuntimeException('mysql timeout');
                    }
                    defer(function () {
                        $this->pool->push($this->mysql);
                    });
                } else {
                    throw new \RuntimeException('pool length < 0');
                }
            });
        });
        return $this->mysql;
    }

    private function __clone() {

    }
}